<?php
/**
 * @name /lib/private/Item.php
 * @author Kimberly Berger <knb4850@esu.edu>
 * @version 2011.03.30
 * 
 * An item class to manage items
 * 
 */

/**
* Item class.
*
*/
class Item {
    /**
    * Item identification.
    *
    * @var integer
    */
         var $ItemId;
    /**
    * Item name.
    *
    * @var string
    */
         var $Name;
    /**
    * Item verified.
    *
    * @var integer
    */
        var $Verified;
    /**
    * Item notes.
    *
    * @var string
    */
        var $Notes;
    /**
    * Item quantity.
    *
    * @var integer
    */
		var $Quantity;
    /**
    * Estimated value of an item
    *
    * @var double
    */
        var $EstimatedValue;
    /**
     * Tag Identification
     *
     * @var integer
     */
        var $TagId;
     /**
      * Tag name
      *
      * @var string
      */
        var $TagName;
    /**
    * The tags of the item.
    *
    * @private
    * @var string[]
    */
	var $_Tags;
  /**
   * The total amount of items needed by all orphanages.
   *
   * @readonly
   * @var integer
   */
  var $AmountNeeded;
	
/* Methods:
	
	Item()
	
  "GET":
	Item[] GetItems(int offset, int maxResults)
	bool Exists(int itemId)
	string ToString()

  "SCUD":
	bool Load(int itemId)
	bool Create(name)
	bool Save()
	static bool Delete(int itemId)
	
  Custom:
   GetItemIdByItemName(name)
   CheckItemValidation(ItemId)
   IsVerified()
   
   HasTag($item)
   TagItem($tag)
   UntagItem($tag)
   
   GetTags()
   CreateTag($tagname)
   DeleteTag($tagname)
   
*/
    /**
    *
    * Constructor.
    *
    */
    function Item(){
            $this->ItemId = 0;
            $this->Name = '';
            $this->Verified = 0;
            $this->Notes = '';
            $this->Quantity = 0;
            $this->EstimatedValue = 0;
            $this->AmountNeeded = 0;
			$this->_Tags = array();
    }
	
	/**
    * Generates a list of items.
    *
    * @param offset, maxResults
    * @return string[]
    */
    function GetItems($offset =0, $maxResults=0){
		$objects = array();
        $db = new DB();
		$query = "SELECT ItemId FROM items ORDER BY ItemId";
		if ($maxResults && $maxResults * 1 == $maxResults){
			$query .= " LIMIT $maxResults";
			if ($offset && $offset * 1 == $offset)
				$query .= " OFFSET $offset";
		}
		elseif ($offset && $offset *1 == $offset)
			$query .= " LIMIT 99999999 OFFSET $offset";
		$itemids = $db->QueryCol($query);
		if(is_array($itemids)){
			foreach ($itemids as $id){
				$objects[count($objects)] = new Item();
				$objects[count($objects) -1 ]->Load($id);
			}
		}
         return $objects;
    }
	
	/**
    * Determines if a item exists or not based on $ItemId.
    *
    * @param integer
    * @return boolean
    */
    function Exists($itemId){
        $db = new DB();
        return ($db->QueryVal("SELECT ItemId FROM items WHERE ItemId='" . addslashes($itemId) . "' LIMIT 1;") > 0);
    }
	
	 /**
    * Lists the attributes about an item
    *
    * @return string
    */
    function ToString($del = '<br />'){
            $str = "";
			$str .= 'ItemId = ' . $this->ItemId . $del;
			$str .= 'ItemName = ' . $this->Name . $del;
			$str .= 'Quantity = ' . $this->Quantity . $del;
			$str .= 'Verified = ' . $this->Verified . $del;
			$str .= 'Notes = ' . $this->Notes .  $del;
			$str .= 'EstimatedValue = ' . $this->EstimatedValue . $del;
			$str .= 'AmountNeeded = ' . $this->AmountNeeded . $del;
			$str .= 'Tags: [';
			if(is_array($this->_Tags))
				for($i = 0; $i <count($this->_Tags); $i++)
					$str .= ($i ? ', ' : '') . $this->_Tags[$i];
			$str .= "]" . $del;
			return $str;
	}
	
	
    /**
    *
    * Loads the item information.
    * Returns a true on success; a false on failure
    *
    *  @param integer
    *  @return boolean
    */
    function Load($itemId){
            if(!Item::Exists($itemId)) // don't try to load an item that doesn't exist
                   return false;
            else{
            $db = new DB();
            $data = $db->QueryRow("
              SELECT
                i.ItemId,
                i.ItemName,
                i.IsVerified,
                i.Notes,
                i.QuantityStored,
                i.EstimatedValue,
                IFNULL(
                  (
                    SELECT SUM(ni.Quantity-ni.QuantitySent) AS AmountNeeded
                    FROM neededitems ni
                    WHERE ni.ItemId='" . addslashes($itemId) . "'
                  ), '0')
                AS AmountNeeded
              FROM items i
              WHERE
                i.ItemId = '" . addslashes($itemId) . "';"
            );
					//store everything in variables
                    $this->ItemId = $data["ItemId"];
                    $this->Name = $data["ItemName"];
                    $this->Verified = $data["IsVerified"];
                    $this->Notes = $data["Notes"];
                    $this->Quantity = $data["QuantityStored"];
                    $this->EstimatedValue = $data["EstimatedValue"];
                    $this->AmountNeeded = $data['AmountNeeded'];
			//select the tags that the item has 		
			$this->_Tags = $db->QueryCol("SELECT t.TagName From tags t INNER JOIN itemstags it ON t.TagId=it.TagId WHERE it.ItemId='".addslashes($this->ItemId)."';");
			if(!$this->_Tags)
				$this->_Tags = array();
            return true;
            }
    }
	
	/**
    * Creates an item 
    * returns true on success, false on failure.
    *
    * @return boolean
    */
    function Create($name) {
      $name = trim($name);
      // if the item exists and is verified don't create another one;
      // if it doesn't exist or it exists and it's not verified then go ahead create it
      if ($name == '') //make sure the name isn't an empty string
        return false;
      elseif (Item::Exists(Item::GetItemIdByItemName($name)) && (Item::CheckItemValidation(Item::GetItemIdByItemName($name)) == 1))
        return false;
      else {
        $db = new DB();
        $sql = "INSERT INTO items (ItemName) VALUES ('" . addslashes($name) ."');";
        $db->Query($sql);
        $sql = "SELECT LAST_INSERT_ID();";
        $this->ItemId = $db->QueryVal($sql);
        $this->Name = $name;
        if (!$this->Save()) {
          Item::Delete($this->ItemId);
          $this->ItemId = 0;
          $this->Name = '';
          return false;
        }
        return true;
      }
    }
	
    /**
    * Saves changes to a preexisting item
    * returns true on success, false on failure.
    *
    * @return boolean
    */
    function Save(){
		if (!Item::Exists($this->ItemId))
			return false;
        
        $db = new DB();
        $sql = ("UPDATE items SET " . 
				"ItemName='" . addslashes($this->Name) . "', " .
                "IsVerified='" .addslashes($this->Verified) . "', " .
                "Notes='" .addslashes($this->Notes) . "', " .
                "QuantityStored='" . addslashes($this->Quantity) . "', " .
                "EstimatedValue='" .addslashes($this->EstimatedValue)."' " .
                "WHERE " . 
			    "ItemId='".addslashes($this->ItemId)."';");
		$db->Query($sql);			
		$db->Query("DELETE FROM itemstags WHERE ItemId ='".addslashes($this->ItemId)."';");
		foreach($this->_Tags as $tag){
			$tagId = $db->QueryVal("SELECT TagId FROM tags WHERE TagName='".addslashes($tag)."';");
			if($tagId){
				$db->Query("INSERT INTO itemstags(ItemId, TagId) VALUES ('".addslashes($this->ItemId)."', '" .addslashes($tagId)."');");
			}
		}
		return true;
    }

    /**
    * STATIC METHOD
    * Deletes an item based on $ItemId
    * returns true on success, false on failure.
    * @param integer
    * @return boolean
    */
    function Delete($itemId){
		$db = new DB();
		
		if(!(Item::IsDeleteable($itemId))) // check to see if an item actually can be deleted
			return false;
		
		//delete the item's tags before deleting the item
        $db->Query("DELETE FROM itemstags WHERE ItemId ='".addslashes($itemId)."';");
		//then delete the item
		$db->Query("DELETE FROM items Where ItemId ='".addslashes($itemId)."';");
		return true;
    }
	/**
	* Checks to see if the item is able to be deleted
	* returns true of false based on whether or not the item can be deleted
	*
	* @param integer
	* @return boolean
	*/
	function IsDeleteable($itemId){
		if(!Item::Exists($itemId))
			 return false;//if I don't exist I can't be deleted
		$db = new DB();
		$sqldonated = "SELECT Count(ItemId) FROM donateditems di WHERE ItemId = '" . addslashes($itemId) . "';"; // checked to see if the item is a donateditem
		$sqltrip = "SELECT Count(ItemId) FROM tripitems WHERE ItemId = '" . addslashes($itemId) . "';"; // check to see if the item is on a trip
		
		// check  to see if the item is a trip or is a donateditem
		if(($db->QueryVal($sqltrip) > 0) || ($db->QueryVal($sqldonated) > 0)){ 
			$sqlverified = "SELECT IsVerified FROM items WHERE ItemId = '" . addslashes($itemId) . "' AND IsVerified='1';";
			
			if($db->QueryVal($sqlverified != 1))
				return true;// if the item is not verified you can delete it
			else				
				return false; // the item cannot be deleted if it is verified and linked to a trip or donateditem
		}
		else 
			return true; //if you aren't linked to a trip or donateditem then do ahead delete it
	}
    

    /**
    * STATIC METHOD
    * Gets the $ItemId by using the $Name.
    * Returns a true on success; a false on failure
    *
    *  @param string
    *  @return integer
    */
    function GetItemIdByItemName($Name){
            $db = new DB();
            $ItemId = $db->QueryVal("SELECT ItemId FROM items Where ItemName='" . addslashes($Name) . "';");
            return $ItemId;
    }
    /**
    * STATIC METHOD
    * Checks whether the item is validated or not
    * Returns a 1  or 0
    *
    *  @param string
    *  @return integer
    */
	function CheckItemValidation($ItemId){
		$db = new DB();
        $validationValue = $db->QueryVal("SELECT IsVerified FROM items Where ItemId='" . addslashes($ItemId) . "';");
        return $validationValue;
	}
	
	/** 
	* Accepts a user query, an optional verified field and an array of tags
	* Returns an array of Items
	*
	* @param string $query
	* @param array $tags
	* @param boolean $isVerfied
	* @return Item[]
	*/
	function FilteredSearch($query = '', $tags = false, $isVerified = -1) {
		$query = trim($query);

		$db = new DB();
		$sql = "SELECT i.ItemId FROM items i ";
    if(is_array($tags) && count($tags) == 1 && trim($tags[0]) == '')
      $tags = "";
		elseif(is_array($tags) && count($tags)) {
			$tagCount = count($tags);
			array_walk($tags, function(&$t){ 
				$t = addslashes($t);
			});
			$tags = " AND t.TagName IN ('" . implode("', '", $tags) . "')";
			$sql .= "INNER JOIN itemstags it ON i.ItemId=it.ItemId INNER JOIN tags t ON it.TagId=t.TagId ";
		}
		else
			$tags = "";
		
		$namesql1 = " WHERE i.ItemName= '" .addslashes($query) . "' ";
		$namesql2 = " WHERE i.ItemName LIKE '" . addslashes($query) ."%' ";
		$namesql3 = " WHERE i.ItemName LIKE '%". addslashes($query) ."%' ";
		
		$endsql = "";
		if ($isVerified == -1);
		elseif (!$isVerified)
			$endsql = " AND i.IsVerified = '0' ";
		else
			$endsql = " AND i.IsVerfied = '1' ";
		if ($tags)
			$endsql .= " GROUP BY i.ItemId HAVING COUNT(t.TagName)='{$tagCount}'";
		$results = array();
		$newResults = $db->QueryCol($sql . $namesql1 . $tags . $endsql);
		if (is_array($newResults))
			$results = array_merge($results, $newResults);
		$newResults = $db->QueryCol($sql . $namesql2 . $tags . $endsql);
		if (is_array($newResults))
			foreach ($newResults as $nr)
				if (!in_array($nr, $results))
					$results[] = $nr;
		$newResults = $db->QueryCol($sql . $namesql3 . $tags . $endsql);
		if (is_array($newResults)){
			foreach ($newResults as $nr){
				if (!in_array($nr, $results))
					$results[] = $nr;
			}
		}
		$items = array();
		foreach($results as $result){
			$item = new Item();
			$item->Load($result);
			$items[] = $item;
		}
		return $items;
	}	

	
    /**
    * Creates a relationship between an Item and a Tag
    * Returns true if succeeds
    *
	* @param string
    * @return boolean
    */
    function TagItem($tag)
    {
        if($this->HasTag($tag))
             return false;
        
         $db = new DB();
		 $tagCheck = $db->QueryVal("SELECT TagName FROM tags WHERE TagName = '" .addslashes($tag)."' LIMIT 1;");
		if (!$tagCheck){
			Item::CreateTag($tag);
			$this->_Tags[count($this->_Tags)] = $tag;
			return true;
		}
		else
			$this->_Tags[count($this->_Tags)] = $tag;
         return true;
        
    }
    

    /**
    * Deletes a relationship between an Item and a Tag
    *
	* @param string
    * @return boolean
    */
     function UntagItem($tag)
    {
        if(!($this->HasTag($tag)))
              return false;
        else{
			$db = new DB();
			$tagCheck = $db->QueryVal("SELECT TagName FROM tags WHERE TagName = '" .addslashes($tag)."' LIMIT 1;");
			if (!$tagCheck)
				return false;
			else{
				$newTags = array();
				foreach($this->_Tags as $newTag)
					if($newTag != $tag)
						$newTags [count($newTags)] = $newTag;
				$this->_Tags = $newTags;
				return true;
			}
		}
      }

     /**
     * Returns an array of tags that an item has
     *
	 * @param string
     * @return bool
     */
     function HasTag($tag){
        $found = false;
		$tag = trim(strtolower($tag));
		for ($i = 0; $i < count($this->_Tags) && !$found; $i++)
			$found = (trim(strtolower($this->_Tags[$i])) == $tag);
		return $found;
      }
     /**
     * Returns all tags in the DB
     *
     * @return TagNames[]
     */
     function GetTags()
     {
        $db = new DB();
        $tagNames = $db->QueryCol("SELECT TagName FROM tags ORDER BY TagName;");
		 if(!$tagNames)
			$tagNames = array();
         return $tagNames;
    }
	/**
	* Creates a Tag if it is not already in the database
	* 
	* @param string
	* @return bool
	*/
	function CreateTag($tag){
		$db = new DB();
		$tagId = $db->QueryVal("SELECT TagId FROM tags Where TagName ='".addslashes($tag)."';");
		if ($tagId)
			return false;
		else{
			$db->Query("INSERT INTO tags (TagName) VALUES ('".addslashes($tag)."');");
			return true;
		}
	}
	
	/**
	* Deletes a Tag if it exists
	* 
	* @param string
	* @return bool
	*/
	function DeleteTag($tag){
		$db = new DB();
		$tagId = $db->QueryVal("SELECT TagId FROM tags WHERE TagName = '". addslashes($tag) . "' LIMIT 1;");
		if(!$tagId)
			return false;
		else{			
			$db->Query("DELETE FROM itemstags WHERE TagId = ' " . addslashes($tagId) . "';");
			$db->Query("DELETE FROM tags WHERE TagId = '".addslashes($tagId) . "';");
			return true;
		}

	}
	
	function UntagAllTags(){
		foreach($this->_Tags as $tag)
			$this->UntagItem($tag);
	}

  /**
    * Determines if an item is verified or not.
    *
    * @return bool
    */
  function IsVerified() {
    return ($this->Verified == 1);
  }
}